package com.hcc.flow.server.service.sys;

import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.CacheManager;
import org.springframework.cache.ehcache.EhCacheCacheManager;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.ConvertingCursor;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.stereotype.Service;

import com.hcc.flow.server.common.advice.RRException;
import com.hcc.flow.server.common.utils.StringUtilsV2;

import net.sf.ehcache.Cache;
import net.sf.ehcache.Element;

@Service
public class RedisServer {

	private static final Logger log = LoggerFactory.getLogger("adminLogger");
	@Value("${system.config.cache.redis-or-ehcache}")
	private String redisOrEhcache;
	private static Boolean cacheRedis;
	
	private static RedisTemplate<String, Object> redisTemplate;
	private static CacheManager manager;
	private static String defaultCacheGroupName = "sys";
	private static long defaultRedisTime = 7200;// redis默认缓存时间秒，ehcache在xml中配置

	@Autowired
	public void setManager(CacheManager manager) {
		cacheRedis = "redis".equals(redisOrEhcache);
		log.debug("应用初始化中，使用的缓存为:{}",redisOrEhcache);
		if(cacheRedis==null){
			throw new RRException("--------------cacheRedis=null--------");
			//return;
		}
		if (!cacheRedis)
			RedisServer.manager = manager;
	}

	@Autowired
	public void setRedisTemplate(RedisTemplate<String, Object> redisTemplate) {
		cacheRedis = "redis".equals(redisOrEhcache);
		if(cacheRedis==null){
			throw new RRException("--------------cacheRedis=null--------");
			//return;
		}
		if (cacheRedis)
			RedisServer.redisTemplate = redisTemplate;
	}

	private static Cache cache(String cacheName) {
		net.sf.ehcache.CacheManager cacheManager = ((EhCacheCacheManager) manager).getCacheManager();
		if (!cacheManager.cacheExists(cacheName))
			cacheManager.addCache(cacheName);
		return cacheManager.getCache(cacheName);
	}

	/**
	 * 获取缓存的值
	 * 
	 * @param cacheGroupName
	 *            缓存的分组名
	 * @param key
	 *            缓存的key
	 * @return
	 */
	public static Object getCacheValue(String cacheGroupName, String key) {
		if (cacheGroupName == null) {
			cacheGroupName = defaultCacheGroupName;
		}
		if (StringUtilsV2.isBlank(key))
			return null;
		if (cacheRedis) {
			Object cacheValue = redisTemplate.opsForValue().get(cacheGroupName + ":" + key);
			return cacheValue != null ? cacheValue : null;
		}
		Element e = cache(cacheGroupName).get(key);
		return e != null ? e.getObjectValue() : null;
	}

	/**
	 * 设置缓存值
	 * 
	 * @param cacheGroupName
	 *            缓存的分组名
	 * @param key
	 *            缓存的key
	 * @param value
	 *            缓存的值
	 * @param time
	 *            缓存有效时间（ehcahe可以不传，因为是在xml中配置）
	 */
	public static void setCacheValue(String cacheGroupName, String key, Object value, Long time) {
		if (cacheGroupName == null) {
			cacheGroupName = defaultCacheGroupName;
		}
		if (StringUtilsV2.isBlank(key))
			return;
		if (cacheRedis) {
			redisTemplate.opsForValue().set(cacheGroupName + ":" + key, value, time != null ? time : defaultRedisTime,
					TimeUnit.SECONDS);
		} else {
			Element e = new Element(key, value);
			cache(cacheGroupName).put(e);
		}
	}

	/**
	 * 删除key值
	 * 
	 * @param cacheGroupName
	 * @param key
	 * @return
	 */
	public static boolean remove(String cacheGroupName, String key) {
		if (cacheGroupName == null) {
			cacheGroupName = defaultCacheGroupName;
		}
		if (StringUtilsV2.isBlank(key))
			return false;
		if (cacheRedis) {
			return redisTemplate.delete(cacheGroupName + ":" + key);
		}
		return cache(cacheGroupName).remove(key);
	}

	public static void removeKeys(String cacheGroupName, Set<String> keys) {
		if (keys.size() == 0)
			return;
		for (String key : keys) {
			remove(cacheGroupName, key);
		}
	}

	public static void removeCacheGroupNameDownAll(String cacheGroupName) {
		if (cacheGroupName == null) {
			cacheGroupName = defaultCacheGroupName;
		}
		if (cacheRedis) {
			deleteRedisKeySeach(cacheGroupName + ":");
		}
		cache(cacheGroupName).removeAll();
	}

	public static void deleteRedisKeys(Set<String> keys) {
		if (keys.size() == 0)
			return;
		if (cacheRedis) {
			redisTemplate.delete(keys);
			log.info("redis中某批数据被清空,{}", keys);
		}
	}

	public static void deleteRedisKeySeach(String keySeach) {
		if (StringUtilsV2.isBlank(keySeach))
			return;
		// Set<String> keys = redisTemplate.keys(keySeach + "*");
		Set<String> keys = assembleScanKeys(keySeach + "*", 100000L);
		if (keys.size() > 0) {
			// redisTemplate.delete(keys);
			// log.info("redis中某批量数据被清空,{}", keys);
			log.info("redis中某批量数据清空-begin");
			keys.parallelStream().forEach(System.out::println);
			log.info("redis中某批量数据清空-end");
		}
	}

	public static void deleteRedisKeysSeach(Set<String> keysSeach) {
		if (redisTemplate == null) {
			return;
		}
		if (keysSeach.size() == 0) {
			return;
		}
		Set<String> keys = new HashSet<>();
		Set<String> keyseacs;
		for (String keySeach : keysSeach) {
			// keyseacs = redisTemplate.keys(keySeach + "*");
			keyseacs = assembleScanKeys(keySeach + "*", 100000L);
			if (keyseacs.size() > 0) {
				keys.addAll(keyseacs);
			}
		}
		redisTemplate.delete(keys);
		if (keys.size() > 0) {
			// log.info("redis中某批量数据被清空,{}", keys);
			log.info("redis中某批量数据清空-begin");
			keys.parallelStream().forEach(System.out::println);
			log.info("redis中某批量数据清空-end");
		}
	}

	/**
	 * 组装 scan 的结果集
	 */
	private static HashSet<String> assembleScanKeys(String pattern, Long limit) {
		HashSet<String> set = new HashSet<>();
		Cursor<String> cursor = scan(pattern, limit);
		while (cursor.hasNext()) {
			set.add(cursor.next());
		}
		try {
			cursor.close();
		} catch (Exception e) {
			log.error("关闭 redis connection 失败");
		}
		return set;
	}

	/**
	 * 自定义 redis scan 操作
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	private static Cursor<String> scan(String pattern, Long limit) {
		ScanOptions options = ScanOptions.scanOptions().match(pattern).count(limit).build();
		RedisSerializer<?> redisSerializer = redisTemplate.getKeySerializer();
		return (Cursor<String>) redisTemplate.executeWithStickyConnection(new RedisCallback() {
			@Override
			public Object doInRedis(RedisConnection redisConnection) throws DataAccessException {
				return new ConvertingCursor<>(redisConnection.scan(options), redisSerializer::deserialize);
			}
		});
	}
}
